﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Web;
using System.Web.Compilation;
using System.IO;
using System.Collections.Specialized;
using System.Linq.Expressions;
using System.Data;

namespace System.Web.Mvc {
    public static class SelectExtension {
        
        
        #region Select box
        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource) {
            return Select(helper, htmlName, dataSource, "", "", null, 0, false, null);
        }
        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="selectedValue">The value that should be selected</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource, object selectedValue) {

            return Select(helper, htmlName, dataSource, "", "", selectedValue, 0, false, null);
        }
        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource, string textField, string valueField) {
            return Select(helper, htmlName, dataSource, textField, valueField, null, 0, false, null);
        }

        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text & value</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource, string textField) {
            return Select(helper, htmlName, dataSource, textField, textField, null, 0, false, null);
        }

        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        /// <param name="selectedValue">The value that should be selected</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource, string textField, string valueField, object selectedValue) {
            return Select(helper, htmlName, dataSource, textField, valueField, selectedValue,0,false, null);
        }
        
        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        /// <param name="selectedValue">The value that should be selected</param>
        /// <param name="htmlAttributes">Any attributes you want set on the select tag. Use anonymous-type declaration for this: new{class=cssclass}</param>
        public static string Select(this HtmlHelper helper, string htmlName, object dataSource, string textField,
            string valueField, object selectedValue, int size, bool multiple, object htmlAttributes) {
            //input formats
            string selectFormat = "\t<select name=\"{0}\" id=\"{0}\" {1}>" + Environment.NewLine + "{2}" + Environment.NewLine + "\t</select>";
            string optionFormat = "\t\t<option value=\"{0}\" {1}>{2}</option>" + Environment.NewLine;

            Hashtable setHash = HtmlExtensionUtility.GetPropertyHash(htmlAttributes);

            //output
            StringBuilder sbOptions = new StringBuilder();
            DataTable tbl = MvcControlDataBinder.EvalDataSource(dataSource, textField, valueField);

            //loop the source
            foreach (DataRow dr in tbl.Rows) {
                string selectedFlag = string.Empty;
                string thisText = dr[1].ToString();
                string thisValue=dr[0].ToString();

                if (selectedValue != null) {
                    if (HtmlExtensionUtility.AreEqual(selectedValue, dr[0]))
                        selectedFlag = " selected=\"true\" ";
                }
                sbOptions.AppendFormat(optionFormat, helper.Encode(thisValue.ToString()), selectedFlag, helper.Encode(thisText));
            }

            string attributeList = string.Empty;
            if (setHash != null)
                attributeList = setHash.ToAttributeList();

            if (multiple)
                attributeList += " multiple ";

            if(size>0)
                attributeList += " size= "+size.ToString();

            return string.Format(selectFormat, htmlName, attributeList, sbOptions.ToString());
        }




        #endregion

        #region List box
        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource) {
            return ListBox(helper, htmlName, dataSource, 10, false, "", "", null, false);
        }

        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size) {
            return ListBox(helper, htmlName, dataSource, size, false, "", "", null, false);
        }

        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, IEnumerable selectedValues) {
            return ListBox(helper, htmlName, dataSource, size, false, "", "", selectedValues, false);
        }


        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        /// <param name="multiple">Whether the user can select multiple values</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, bool multiple) {
            return ListBox(helper, htmlName, dataSource, size, multiple, "", "", null, false);
        }

        /// <summary>
        /// Creates an HTML Select drop-down based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        /// <param name="multiple">Whether the user can select multiple values</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, bool multiple, IEnumerable selectedValues) {
            return ListBox(helper, htmlName, dataSource, size, multiple, "", "", selectedValues, false);
        }


        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="selectedValue">The value that should be selected</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, IEnumerable selectedValues) {

            return ListBox(helper, htmlName, dataSource, 10, false, "", "", selectedValues, null);
        }
        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, string textField, string valueField) {
            return ListBox(helper, htmlName, dataSource, 10, false, textField, valueField, null, null);
        }

        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, string textField, string valueField) {
            return ListBox(helper, htmlName, dataSource, size, false, textField, valueField, null, null);
        }

        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="size">The number of rows to display on screen</param>
        /// <param name="multiple">Whether the user can select multiple values</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, bool multiple, string textField, string valueField) {
            return ListBox(helper, htmlName, dataSource, size, multiple, textField, valueField, null, null);
        }
        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        /// <param name="selectedValue">The value that should be selected</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, string textField, string valueField, IEnumerable selectedValues) {
            return ListBox(helper, htmlName, dataSource, 10, false, textField, valueField, selectedValues, null);
        }

        /// <summary>
        /// Creates an HTML ListBox based on the passed-in datasource.
        /// </summary>
        /// <param name="htmlName">The name of the control for the page</param>
        /// <param name="dataSource">IEnumerable, IQueryable, DataSet, DataTable, or IDataReader</param>
        /// <param name="size">The number of rows to display on screen</param>
        /// <param name="multiple">Whether the user can select multiple values</param>
        /// <param name="textField">The datasource field to use for the the display text</param>
        /// <param name="valueField">The datasource field to use for the the control value</param>
        /// <param name="selectedValue">The value that should be selected</param>
        /// <param name="htmlAttributes">Any attributes you want set on the select tag. Use anonymous-type declaration for this: new{class=cssclass}</param>
        public static string ListBox(this HtmlHelper helper, string htmlName, object dataSource, int size, bool multiple, string textField,
            string valueField, IEnumerable selectedValues, object htmlAttributes) {
            
            //input formats
            string selectFormat = "\t<select name=\"{0}\" id=\"{0}\" {1}>" + Environment.NewLine + "{2}" + Environment.NewLine + "\t</select>";
            string optionFormat = "\t\t<option value=\"{0}\" {1}>{2}</option>" + Environment.NewLine;

            Hashtable setHash = HtmlExtensionUtility.GetPropertyHash(htmlAttributes);

            //output
            StringBuilder sbOptions = new StringBuilder();
            DataTable tbl = MvcControlDataBinder.EvalDataSource(dataSource, textField, valueField);

            //loop the source
            foreach (DataRow dr in tbl.Rows) {
                string selectedFlag = string.Empty;
                string thisText = dr[1].ToString();
                string thisValue = dr[0].ToString();
                bool isSelected = false;
                
                if (selectedValues != null) {
                    IEnumerator en = selectedValues.GetEnumerator();
                    while (en.MoveNext()) {
                        isSelected = HtmlExtensionUtility.AreEqual(en.Current, thisValue);
                        if (isSelected)
                            break;
                    }
                }
                if (isSelected)
                    selectedFlag = " selected=\"true\" ";

                sbOptions.AppendFormat(optionFormat, helper.Encode(thisValue.ToString()), selectedFlag, helper.Encode(thisText));
            }

            string attributeList = string.Empty;
            if (setHash != null)
                attributeList = setHash.ToAttributeList();

            if (multiple)
                attributeList += " multiple ";

            if (size > 0)
                attributeList += " size= " + size.ToString();

            return string.Format(selectFormat, htmlName, attributeList, sbOptions.ToString());
        }




        #endregion

    }
}
